package com.Logistics.pddispatch.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.Logistics.truck.TransportLineFeignClient;
import com.Logistics.pddispatch.dto.*;
import com.Logistics.dto.line.TransportLineDto;
import com.Logistics.pddispatch.entity.CacheLine;
import com.Logistics.pddispatch.entity.CacheLineDetail;
import com.Logistics.pddispatch.entity.CacheLineUse;
import com.Logistics.entity.line.LineBean;
import com.Logistics.pddispatch.enums.ScheduleParams;
import com.Logistics.pddispatch.service.CacheLineDetailsService;
import com.Logistics.pddispatch.service.CacheLineService;
import com.Logistics.pddispatch.service.CacheLineUseService;
import com.Logistics.pddispatch.service.TaskRoutePlanningService;
import com.Logistics.mycommon.tools.IDAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 线路规划
 */
@Service
@Slf4j
public class TaskRoutePlanningServiceImpl implements TaskRoutePlanningService {
    @Autowired
    private TransportLineFeignClient transportLineFeignClient;
    @Autowired
    private CacheLineService cacheLineService;
    @Autowired
    private CacheLineDetailsService cacheLineDetailsService;
    @Autowired
    private CacheLineUseService cacheLineUseService;
    /**
     *
     * @param orderClassifyGroupDTOS  分类后的订单
     * @param agencyId 机构ID
     * @param jobId 任务ID
     * @param logId 任务日志ID
     * @param params 规则
     * @return
     */
    @Override
    public List<OrderLineSimpleDTO> execute(List<OrderClassifyGroupDTO> orderClassifyGroupDTOS, String agencyId, String jobId, String logId, String params) {
        List<OrderLineDTO> orderLineDTOS = new ArrayList<>();
        orderClassifyGroupDTOS.stream().filter(item -> "ERROR".equals(item.getKey())).forEach(item -> {
            // TODO 处理无法调度订单
            log.info("异常订单{}条", item.getOrders().size());
        });
        //新订单调度
        orderClassifyGroupDTOS.stream().filter(item ->(item.isNew() && !"ERROR".equals(item.getKey()))).forEach(item ->{
            //递归查找线路信息
            RoutePlanningDTO routePlanningDTO = findLine(0, agencyId, item.getStartAgencyId(), item.getEndAgencyId(), new ArrayList<>());

            //将线路进行拆分聚合
            AnalysisRoutePlanningDTO analysisRoutePlanningDTO = new AnalysisRoutePlanningDTO(routePlanningDTO,
                    item.getStartAgencyId(), item.getEndAgencyId()).build();
            //将子缓存线路和父缓存线路进行绑定
            Map<CacheLine,List<CacheLineDetail>> map = analysisRoutePlanningDTO.get();

            //将所有缓存线路与数据库线路数据进行比较
            map = mergeLine(map);

            //根据参数选择路线
            CacheLineDetail cacheLineDetail = defaultLine(map, params);
            if (cacheLineDetail == null){
                return;
            }

            //将线路与订单关联
            relationOrder(cacheLineDetail,item.getId());
            //添加订单与线路的关联信息
            orderLineDTOS.add(new OrderLineDTO(cacheLineDetail,item));
        });

        // 中转订单调度
        orderClassifyGroupDTOS.stream().filter(item ->(!item.isNew() && !"ERROR".equals(item.getKey()))).forEach(item ->{
            String id = item.getId();
            //获取线路信息
            CacheLineDetail cacheLineDetail = findBeforeLine(id, agencyId);
            //添加订单与线路的关联信息
            orderLineDTOS.add(new OrderLineDTO(cacheLineDetail,item));
        });

        //构建实际使用线路模型
        List<OrderLineSimpleDTO> list = buildOrderLineSimpleDTOS(orderLineDTOS);


        return list;
    }

    /**
     * 将真实线路和订单分类绑定
     * @param orderLineDTOS
     * @return
     */
    private List<OrderLineSimpleDTO> buildOrderLineSimpleDTOS(List<OrderLineDTO> orderLineDTOS) {
        Map<String,List<OrderClassifyGroupDTO>> listMap = new HashMap<>();
        Map<String,CacheLineDetail> detailMap = new HashMap<>();

        orderLineDTOS.forEach(item->{
            OrderClassifyGroupDTO classifyGroupDTO = item.getOrderClassifyGroupDTO();
            CacheLineDetail cacheLineDetail = item.getCacheLineDetailEntity();

            List<OrderClassifyGroupDTO> list = new ArrayList<>();
            if (detailMap.containsKey(cacheLineDetail.getTransport_line_id())){
                listMap.get(cacheLineDetail.getCache_line_id()).add(classifyGroupDTO);
            }else {
                list.add(classifyGroupDTO);
                listMap.put(cacheLineDetail.getTransport_line_id(),list);
            }
            detailMap.put(cacheLineDetail.getTransport_line_id(),cacheLineDetail);
        });

        List<OrderLineSimpleDTO> simpleDTOS = new ArrayList<>();
        detailMap.forEach((lineId,cacheDetail)->{
            simpleDTOS.add(new OrderLineSimpleDTO(cacheDetail,listMap.get(lineId)));
        });

        return simpleDTOS;
    }

    //获取线路信息
    private CacheLineDetail findBeforeLine(String id, String agencyId) {
        QueryWrapper<CacheLineUse> queryWrapper = new QueryWrapper<>();
        if (StringUtils.hasText(id)){
            queryWrapper.eq("cache_line_id",id);
        }
        CacheLineUse cacheLineUse = this.cacheLineUseService.getOne(queryWrapper);
        QueryWrapper<CacheLineDetail> queryWrapper1 = new QueryWrapper<>();
        if (StringUtils.hasText(cacheLineUse.getCache_line_id())){
            queryWrapper1.eq("cache_line_id",cacheLineUse.getCache_line_id());
        }
        if (StringUtils.hasText(agencyId)){
            queryWrapper1.eq("start_agency_id",agencyId);
        }

        return this.cacheLineDetailsService.getOne(queryWrapper1);
    }

    //将线路与订单关联
    private void relationOrder(CacheLineDetail cacheLineDetail, String id) {
        CacheLineUse cacheLineUse = new CacheLineUse();
        cacheLineUse.setId(new IDAlgorithm(0L,0L).nextIdAsString());
        cacheLineUse.setCache_line_id(cacheLineDetail.getCache_line_id());
        cacheLineUse.setOrder_classify_id(id);
        cacheLineUse.setCreate_date(new Date());
        this.cacheLineUseService.save(cacheLineUse);
    }

    //根据规则选择路线
    private CacheLineDetail defaultLine(Map<CacheLine, List<CacheLineDetail>> map, String params) {
        if (map.size() == 0){
            return null;
        }

        List<CacheLine> cacheLines = map.keySet().stream().collect(Collectors.toList());

        if (cacheLines.size() == 1){
            return map.get(cacheLines.get(0)).get(0);
        }

        if (ScheduleParams.DISTANCE.getValue().equals(params)){
            cacheLines.sort(Comparator.comparing(CacheLine::getDistance));
        }
        if (ScheduleParams.COST.getValue().equals(params)){
            cacheLines.sort(Comparator.comparing(CacheLine::getCost));
        }
        if (ScheduleParams.ESTIMATEDTIME.getValue().equals(params)){
            cacheLines.sort(Comparator.comparing(CacheLine::getEstimate_time));
        }
        if (ScheduleParams.TRANSFER.getValue().equals(params)){
            cacheLines.sort(Comparator.comparing(CacheLine::getTransfer_count));
        }

        return map.get(cacheLines.get(0)).get(0);
    }

    /**
     * 与数据库中的缓存线路信息进行比对 一致则使用 不一致则新加线路
     * @param map
     * @return
     */
    public Map<CacheLine, List<CacheLineDetail>> mergeLine(Map<CacheLine, List<CacheLineDetail>> map) {
        Set<Map.Entry<CacheLine,List<CacheLineDetail>>> entries = map.entrySet();
        Map<String,List<Map.Entry<CacheLine,List<CacheLineDetail>>>> groupMap = new HashMap<>();
        //将所有父缓存线路根据起点和终点进行分组
        entries.forEach(entry->{
            String key = entry.getKey().getStart_agency_id()+entry.getKey().getEnd_agency_id();
            if (groupMap.containsKey(key)){
                groupMap.get(key).add(entry);
            }else {
                List<Map.Entry<CacheLine,List<CacheLineDetail>> > list = new ArrayList<>();
                list.add(entry);
                groupMap.put(key,list);
            }
        });

        //判断那些线路是不可用的
        Map<String,Integer> deleteLindVerifyKey = new HashMap<>();
        for (Map.Entry<String,List<Map.Entry<CacheLine,List<CacheLineDetail>>>> entry : groupMap.entrySet()) {
            List<Map.Entry<CacheLine,List<CacheLineDetail>>> list = entry.getValue();
            String notStartAgencyId = "";
            String notEndAgencyId = "";
            for (Map.Entry<CacheLine,List<CacheLineDetail>> mapEntry : list){
                CacheLine cacheLine = mapEntry.getKey();
                String cacheLineId = cacheLineService.check(cacheLine.getVerify_key());
                //检验线路是否可用
                if (StringUtils.isEmpty(cacheLineId)){
                    //线路不可用 记录一下起点与终点
                    notStartAgencyId = cacheLine.getStart_agency_id();
                    notEndAgencyId = cacheLine.getEnd_agency_id();
                }
            }
            if (StringUtils.hasText(notStartAgencyId) && StringUtils.hasText(notEndAgencyId)){
                Integer version = this.cacheLineService.deleteOldAndGetNewVersion(notStartAgencyId,notEndAgencyId);
                for (Map.Entry<CacheLine,List<CacheLineDetail>> cacheLineListEntry : list) {
                    deleteLindVerifyKey.put(cacheLineListEntry.getKey().getVerify_key(),version);
                }
            }
        }

        //对可执行的线路查询赋值 对不可执行的线路进行新增
        for (Map.Entry<CacheLine,List<CacheLineDetail>> lineListEntry : map.entrySet()) {
            CacheLine cacheLine = lineListEntry.getKey();
            List<CacheLineDetail> lineDetails = lineListEntry.getValue();
            //不可执行的线路进行新增
            if (deleteLindVerifyKey.containsKey(cacheLine.getVerify_key())){
                cacheLine.setVersion(deleteLindVerifyKey.get(cacheLine.getVerify_key()));
                this.cacheLineService.save(cacheLine);
                 lineDetails = lineDetails.stream().map(item->{
                    item.setId(new IDAlgorithm(0L,0L).nextIdAsString());
                    return item;
                }).collect(Collectors.toList());
                map.put(cacheLine,lineDetails);
            }else {
                //可执行的线路查询赋值
                String cacheLineId = this.cacheLineService.check(cacheLine.getVerify_key());
                cacheLine.setId(cacheLineId);
                QueryWrapper<CacheLineDetail> queryWrapper = new QueryWrapper<>();
                lineDetails = this.cacheLineDetailsService.list(queryWrapper);
                map.put(cacheLine,lineDetails);
            }
        }

        return map;
    }

    /**
     * 递归查询路线信息
     * @param recursionCount 递归次数(深度)
     * @param agencyId 当前机构ID
     * @param startAgencyId 起始机构
     * @param endAgencyId 目的机构
     * @param superiorStarts 上级起点机构
     * @return
     */
    private RoutePlanningDTO findLine(int recursionCount, String agencyId, String startAgencyId, String endAgencyId,
                                      ArrayList<String> superiorStarts) {
        //创建一个routePlanningDTO对象用于存储直达线路和转运线路信息
        RoutePlanningDTO routePlanningDTO = new RoutePlanningDTO(++recursionCount);
        List<String> feasibleIds = new ArrayList<>();
        //查询当前网点的直达线路信息
        List<LineBean> lineBeans = findDirectLine(startAgencyId,endAgencyId,agencyId);
        if (lineBeans!=null && lineBeans.size()>0){
            routePlanningDTO.setFeasibleLineBeans(lineBeans); //将直达线路设置到routePlanningDTO
            feasibleIds.addAll(lineBeans.stream().map(item ->item.getId()).collect(Collectors.toList()));
        }
        //查询当前网点所有起始路线
        lineBeans = findStartLine(startAgencyId,agencyId);
        superiorStarts.add(startAgencyId);

        // 1 过滤已经直达的路线，2 过滤上一级的机构（本次查询到的路线 终点不能是上一级或者在上级的机构，若不过滤，理论上会出现死循环）
        lineBeans = lineBeans.stream().filter(item->(!feasibleIds.contains(item.getId())) && !superiorStarts.contains(item.getId())).collect(Collectors.toList());
        if (lineBeans.size()>0){
            routePlanningDTO.add(lineBeans);
            for (LineBean line : lineBeans) {
                String lineEndAgencyId = line.getEnd_agency_id();
                RoutePlanningDTO routePlanningDTO1 = findLine(recursionCount,agencyId,lineEndAgencyId,endAgencyId,
                        superiorStarts);
                routePlanningDTO.put(line.getId(),routePlanningDTO1);
            }
        }

        return routePlanningDTO;
    }

    /**
     * 查询当前网点所有起始路线
     * @param startAgencyId 起始机构ID
     * @param agencyId 当前机构ID
     * @return
     */
    private List<LineBean> findStartLine(String startAgencyId, String agencyId) {
        TransportLineDto transportLineDto = new TransportLineDto();
        transportLineDto.setStart(startAgencyId);
        transportLineDto.setAgencyId(agencyId);
        return this.transportLineFeignClient.findDirectLine(transportLineDto);
    }

    /**
     * 查询当前网点所有直达的线路信息
     * @param startAgencyId  起始机构ID
     * @param endAgencyId 终点机构ID
     * @param agencyId 当前机构ID
     * @return
     */
    private List<LineBean> findDirectLine(String startAgencyId, String endAgencyId, String agencyId) {
        TransportLineDto transportLineDto  = new TransportLineDto();
        transportLineDto.setStart(startAgencyId);
        transportLineDto.setEnd(endAgencyId);
        transportLineDto.setAgencyId(agencyId);
        return this.transportLineFeignClient.findDirectLine(transportLineDto);
    }
}
